"""
邮件服务类
处理邮件发送、模板管理、用户消息等功能
"""

import json
import uuid
from typing import List, Optional, Dict, Any, Tuple
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, desc
from fastapi_mail import MessageSchema, MessageType
from jinja2 import Template, TemplateError

from app.core.email_config import get_mail_client, EmailTemplate as EmailTemplateEnum
from app.core.logging import get_logger
from app.core.db_utils import create_optimized_query, PaginationResult
from app.models.user import User
from app.models.email_message import EmailMessage, EmailTemplate, EmailQueue, EmailStatus, EmailType, EmailPriority
from app.schemas.email import (
    EmailSendRequest, EmailTemplateRequest, EmailBatchRequest, UserMessageRequest,
    EmailListParams, EmailTemplateCreate, EmailTemplateUpdate
)
from app.middleware.exception_middleware import BusinessException, ResourceNotFoundException

logger = get_logger(__name__)


class EmailService:
    """邮件服务类"""
    
    def __init__(self, db: Session):
        self.db = db
        self.mail_client = get_mail_client()
    
    async def send_email(
        self,
        request: EmailSendRequest,
        sender_user: Optional[User] = None
    ) -> EmailMessage:
        """
        发送邮件
        
        Args:
            request: 邮件发送请求
            sender_user: 发送者用户（可选，系统邮件为None）
            
        Returns:
            EmailMessage: 邮件记录
        """
        try:
            # 创建邮件记录
            email_message = EmailMessage(
                sender_id=sender_user.id if sender_user else None,
                sender_email=sender_user.email if sender_user else "system@fastapi-platform.com",
                sender_name=sender_user.full_name if sender_user else "FastAPI Platform",
                recipient_email=request.recipient_email,
                recipient_name=request.recipient_name,
                subject=request.subject,
                body_text=request.body_text,
                body_html=request.body_html,
                email_type=EmailType.USER_MESSAGE if sender_user else EmailType.NOTIFICATION,
                priority=EmailPriority(request.priority.value),
                status=EmailStatus.PENDING
            )
            
            self.db.add(email_message)
            self.db.commit()
            self.db.refresh(email_message)
            
            # 发送邮件
            await self._send_email_message(email_message)
            
            return email_message
            
        except Exception as e:
            logger.error(f"发送邮件失败: {e}")
            self.db.rollback()
            raise BusinessException(f"发送邮件失败: {str(e)}")
    
    async def send_template_email(
        self,
        request: EmailTemplateRequest,
        sender_user: Optional[User] = None
    ) -> EmailMessage:
        """
        使用模板发送邮件
        
        Args:
            request: 模板邮件请求
            sender_user: 发送者用户
            
        Returns:
            EmailMessage: 邮件记录
        """
        try:
            # 获取邮件模板
            template = self.get_template_by_name(request.template_name)
            if not template:
                raise ResourceNotFoundException(f"邮件模板不存在: {request.template_name}")
            
            if not template.is_active:
                raise BusinessException(f"邮件模板已禁用: {request.template_name}")
            
            # 渲染模板
            subject, body_html = self._render_template(template, request.template_data)
            
            # 创建邮件记录
            email_message = EmailMessage(
                sender_id=sender_user.id if sender_user else None,
                sender_email=sender_user.email if sender_user else "system@fastapi-platform.com",
                sender_name=sender_user.full_name if sender_user else "FastAPI Platform",
                recipient_email=request.recipient_email,
                recipient_name=request.recipient_name,
                subject=subject,
                body_html=body_html,
                email_type=template.email_type,
                priority=EmailPriority(request.priority.value),
                template_name=template.name,
                template_data=json.dumps(request.template_data),
                status=EmailStatus.PENDING
            )
            
            self.db.add(email_message)
            self.db.commit()
            self.db.refresh(email_message)
            
            # 发送邮件
            await self._send_email_message(email_message)
            
            return email_message
            
        except Exception as e:
            logger.error(f"发送模板邮件失败: {e}")
            self.db.rollback()
            raise BusinessException(f"发送模板邮件失败: {str(e)}")
    
    async def send_user_message(
        self,
        request: UserMessageRequest,
        sender_user: User
    ) -> EmailMessage:
        """
        发送用户间消息
        
        Args:
            request: 用户消息请求
            sender_user: 发送者
            
        Returns:
            EmailMessage: 邮件记录
        """
        try:
            # 获取收件人用户
            recipient_user = self.db.query(User).filter(User.id == request.recipient_id).first()
            if not recipient_user:
                raise ResourceNotFoundException("收件人用户不存在")
            
            if not recipient_user.is_active:
                raise BusinessException("收件人用户已禁用")
            
            # 使用用户消息模板
            template_data = {
                "sender_name": sender_user.full_name or sender_user.username,
                "sender_email": sender_user.email,
                "recipient_name": recipient_user.full_name or recipient_user.username,
                "message": request.message,
                "subject": request.subject,
                "platform_name": "FastAPI Platform"
            }
            
            template_request = EmailTemplateRequest(
                recipient_email=recipient_user.email,
                recipient_name=recipient_user.full_name,
                template_name="user_message",
                template_data=template_data,
                priority=request.priority
            )
            
            return await self.send_template_email(template_request, sender_user)
            
        except Exception as e:
            logger.error(f"发送用户消息失败: {e}")
            raise BusinessException(f"发送用户消息失败: {str(e)}")
    
    async def send_batch_emails(
        self,
        request: EmailBatchRequest,
        sender_user: Optional[User] = None
    ) -> Tuple[str, List[EmailMessage]]:
        """
        批量发送邮件
        
        Args:
            request: 批量邮件请求
            sender_user: 发送者用户
            
        Returns:
            Tuple[str, List[EmailMessage]]: 批次ID和邮件记录列表
        """
        batch_id = str(uuid.uuid4())
        email_messages = []
        
        try:
            for recipient in request.recipients:
                try:
                    # 创建邮件记录
                    email_message = EmailMessage(
                        sender_id=sender_user.id if sender_user else None,
                        sender_email=sender_user.email if sender_user else "system@fastapi-platform.com",
                        sender_name=sender_user.full_name if sender_user else "FastAPI Platform",
                        recipient_email=recipient["email"],
                        recipient_name=recipient.get("name"),
                        subject=request.subject,
                        body_text=request.body_text,
                        body_html=request.body_html,
                        email_type=EmailType.NOTIFICATION,
                        priority=EmailPriority(request.priority.value),
                        template_name=request.template_name,
                        template_data=json.dumps(request.template_data) if request.template_data else None,
                        status=EmailStatus.PENDING
                    )
                    
                    self.db.add(email_message)
                    self.db.flush()  # 获取ID但不提交
                    
                    # 添加到队列
                    queue_item = EmailQueue(
                        queue_name="batch_email",
                        batch_id=batch_id,
                        email_message_id=email_message.id,
                        scheduled_at=request.scheduled_at or datetime.utcnow(),
                        status=EmailStatus.PENDING
                    )
                    
                    self.db.add(queue_item)
                    email_messages.append(email_message)
                    
                except Exception as e:
                    logger.error(f"创建批量邮件记录失败: {e}")
                    continue
            
            self.db.commit()
            
            # 如果没有计划时间，立即发送
            if not request.scheduled_at:
                await self._process_email_queue(batch_id)
            
            return batch_id, email_messages
            
        except Exception as e:
            logger.error(f"批量发送邮件失败: {e}")
            self.db.rollback()
            raise BusinessException(f"批量发送邮件失败: {str(e)}")
    
    async def _send_email_message(self, email_message: EmailMessage):
        """
        发送单个邮件消息
        
        Args:
            email_message: 邮件消息对象
        """
        try:
            email_message.status = EmailStatus.SENDING
            self.db.commit()
            
            # 准备邮件内容
            message = MessageSchema(
                subject=email_message.subject,
                recipients=[email_message.recipient_email],
                body=email_message.body_html or email_message.body_text,
                subtype=MessageType.html if email_message.body_html else MessageType.plain
            )
            
            # 发送邮件
            await self.mail_client.send_message(message)
            
            # 更新状态
            email_message.status = EmailStatus.SENT
            email_message.sent_at = datetime.utcnow()
            self.db.commit()
            
            logger.info(f"邮件发送成功: {email_message.id} -> {email_message.recipient_email}")
            
        except Exception as e:
            # 更新失败状态
            email_message.status = EmailStatus.FAILED
            email_message.failed_reason = str(e)
            email_message.retry_count += 1
            self.db.commit()
            
            logger.error(f"邮件发送失败: {email_message.id} -> {email_message.recipient_email}, 错误: {e}")
            raise
    
    async def _process_email_queue(self, batch_id: str):
        """
        处理邮件队列
        
        Args:
            batch_id: 批次ID
        """
        try:
            # 获取队列中的邮件
            queue_items = self.db.query(EmailQueue).filter(
                and_(
                    EmailQueue.batch_id == batch_id,
                    EmailQueue.status == EmailStatus.PENDING
                )
            ).all()
            
            for queue_item in queue_items:
                try:
                    await self._send_email_message(queue_item.email_message)
                    queue_item.status = EmailStatus.SENT
                    queue_item.processed_at = datetime.utcnow()
                except Exception as e:
                    queue_item.status = EmailStatus.FAILED
                    logger.error(f"队列邮件发送失败: {queue_item.id}, 错误: {e}")
            
            self.db.commit()
            
        except Exception as e:
            logger.error(f"处理邮件队列失败: {e}")
            self.db.rollback()
    
    def _render_template(self, template: EmailTemplate, data: Dict[str, Any]) -> Tuple[str, str]:
        """
        渲染邮件模板
        
        Args:
            template: 邮件模板
            data: 模板数据
            
        Returns:
            Tuple[str, str]: 渲染后的主题和内容
        """
        try:
            # 渲染主题
            subject_template = Template(template.subject_template)
            subject = subject_template.render(**data)
            
            # 渲染内容
            body_template = Template(template.body_template)
            body = body_template.render(**data)
            
            return subject, body
            
        except TemplateError as e:
            logger.error(f"模板渲染失败: {e}")
            raise BusinessException(f"模板渲染失败: {str(e)}")
    
    def get_email_list(self, params: EmailListParams, user_id: Optional[int] = None) -> PaginationResult:
        """
        获取邮件列表
        
        Args:
            params: 查询参数
            user_id: 用户ID（可选，用于过滤用户相关邮件）
            
        Returns:
            PaginationResult: 分页结果
        """
        query = self.db.query(EmailMessage)
        
        # 用户过滤
        if user_id:
            query = query.filter(
                or_(
                    EmailMessage.sender_id == user_id,
                    EmailMessage.recipient_id == user_id
                )
            )
        
        # 构建过滤条件
        filters = {}
        if params.status:
            filters["status"] = EmailStatus(params.status.value)
        if params.email_type:
            filters["email_type"] = EmailType(params.email_type.value)
        if params.sender_email:
            filters["sender_email"] = f"%{params.sender_email}%"
        if params.recipient_email:
            filters["recipient_email"] = f"%{params.recipient_email}%"
        
        # 日期范围过滤
        if params.date_from:
            query = query.filter(EmailMessage.created_at >= params.date_from)
        if params.date_to:
            query = query.filter(EmailMessage.created_at <= params.date_to)
        
        # 搜索过滤
        if params.search:
            query = query.filter(EmailMessage.subject.ilike(f"%{params.search}%"))
        
        return create_optimized_query(
            db=self.db,
            model=EmailMessage,
            filters=filters,
            sort_by="created_at",
            sort_order="desc",
            page=params.page,
            size=params.size
        )
    
    def get_email_by_id(self, email_id: int, user_id: Optional[int] = None) -> Optional[EmailMessage]:
        """
        根据ID获取邮件
        
        Args:
            email_id: 邮件ID
            user_id: 用户ID（可选，用于权限检查）
            
        Returns:
            Optional[EmailMessage]: 邮件对象
        """
        query = self.db.query(EmailMessage).filter(EmailMessage.id == email_id)
        
        # 用户权限检查
        if user_id:
            query = query.filter(
                or_(
                    EmailMessage.sender_id == user_id,
                    EmailMessage.recipient_id == user_id
                )
            )
        
        return query.first()
    
    async def retry_failed_email(self, email_id: int) -> EmailMessage:
        """
        重试发送失败的邮件
        
        Args:
            email_id: 邮件ID
            
        Returns:
            EmailMessage: 邮件对象
        """
        email_message = self.db.query(EmailMessage).filter(EmailMessage.id == email_id).first()
        if not email_message:
            raise ResourceNotFoundException("邮件不存在")
        
        if not email_message.can_retry:
            raise BusinessException("邮件无法重试发送")
        
        try:
            await self._send_email_message(email_message)
            return email_message
        except Exception as e:
            raise BusinessException(f"重试发送邮件失败: {str(e)}")
    
    def mark_email_as_read(self, email_id: int, user_id: int) -> EmailMessage:
        """
        标记邮件为已读
        
        Args:
            email_id: 邮件ID
            user_id: 用户ID
            
        Returns:
            EmailMessage: 邮件对象
        """
        email_message = self.db.query(EmailMessage).filter(
            and_(
                EmailMessage.id == email_id,
                EmailMessage.recipient_id == user_id
            )
        ).first()
        
        if not email_message:
            raise ResourceNotFoundException("邮件不存在或无权限")
        
        if email_message.status == EmailStatus.SENT and not email_message.read_at:
            email_message.status = EmailStatus.READ
            email_message.read_at = datetime.utcnow()
            self.db.commit()
        
        return email_message
    
    # 模板管理方法
    def create_template(self, request: EmailTemplateCreate) -> EmailTemplate:
        """创建邮件模板"""
        # 检查模板名称是否已存在
        existing = self.db.query(EmailTemplate).filter(EmailTemplate.name == request.name).first()
        if existing:
            raise BusinessException(f"模板名称已存在: {request.name}")
        
        template = EmailTemplate(
            name=request.name,
            display_name=request.display_name,
            description=request.description,
            subject_template=request.subject_template,
            body_template=request.body_template,
            email_type=EmailType(request.email_type.value),
            variables=json.dumps(request.variables) if request.variables else None
        )
        
        self.db.add(template)
        self.db.commit()
        self.db.refresh(template)
        
        return template
    
    def get_template_by_name(self, name: str) -> Optional[EmailTemplate]:
        """根据名称获取模板"""
        return self.db.query(EmailTemplate).filter(EmailTemplate.name == name).first()
    
    def get_templates_list(self, page: int = 1, size: int = 20) -> PaginationResult:
        """获取模板列表"""
        return create_optimized_query(
            db=self.db,
            model=EmailTemplate,
            sort_by="created_at",
            sort_order="desc",
            page=page,
            size=size
        )
    
    def update_template(self, template_id: int, request: EmailTemplateUpdate) -> EmailTemplate:
        """更新邮件模板"""
        template = self.db.query(EmailTemplate).filter(EmailTemplate.id == template_id).first()
        if not template:
            raise ResourceNotFoundException("邮件模板不存在")
        
        if template.is_system:
            raise BusinessException("系统模板不允许修改")
        
        # 更新字段
        for field, value in request.dict(exclude_unset=True).items():
            if field == "variables" and value:
                setattr(template, field, json.dumps(value))
            else:
                setattr(template, field, value)
        
        self.db.commit()
        self.db.refresh(template)
        
        return template
    
    def delete_template(self, template_id: int):
        """删除邮件模板"""
        template = self.db.query(EmailTemplate).filter(EmailTemplate.id == template_id).first()
        if not template:
            raise ResourceNotFoundException("邮件模板不存在")
        
        if template.is_system:
            raise BusinessException("系统模板不允许删除")
        
        self.db.delete(template)
        self.db.commit()
    
    def get_email_stats(self, user_id: Optional[int] = None, days: int = 30) -> Dict[str, Any]:
        """
        获取邮件统计信息
        
        Args:
            user_id: 用户ID（可选）
            days: 统计天数
            
        Returns:
            Dict[str, Any]: 统计信息
        """
        # 计算日期范围
        end_date = datetime.utcnow()
        start_date = end_date - timedelta(days=days)
        
        query = self.db.query(EmailMessage).filter(
            EmailMessage.created_at >= start_date
        )
        
        # 用户过滤
        if user_id:
            query = query.filter(EmailMessage.sender_id == user_id)
        
        # 统计各状态邮件数量
        total_sent = query.filter(EmailMessage.status.in_([EmailStatus.SENT, EmailStatus.DELIVERED, EmailStatus.READ])).count()
        total_pending = query.filter(EmailMessage.status == EmailStatus.PENDING).count()
        total_failed = query.filter(EmailMessage.status == EmailStatus.FAILED).count()
        total_delivered = query.filter(EmailMessage.status.in_([EmailStatus.DELIVERED, EmailStatus.READ])).count()
        
        # 计算成功率
        total_emails = total_sent + total_failed
        success_rate = (total_sent / total_emails * 100) if total_emails > 0 else 0
        
        # 获取最近的邮件
        recent_emails = query.order_by(desc(EmailMessage.created_at)).limit(10).all()
        
        return {
            "total_sent": total_sent,
            "total_pending": total_pending,
            "total_failed": total_failed,
            "total_delivered": total_delivered,
            "success_rate": round(success_rate, 2),
            "recent_emails": recent_emails
        }